package com.sunnada.demo.log;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *数据交互层的反射操作
 *
 * @author 李瑞益
 */
@SuppressWarnings("all")
public class DataReflectUtil {

    private final static Logger logger = LoggerFactory.getLogger(TrackLogUtil.class);

    //region 获取数据
    /**
     * 根据传入对象获取dao对象
     * @param object 不知名对象，确保他有对应dao层
     * @param daoSuffix 数据交换层的后缀名，如 DogDao 中的Dao或是DogMapper中的Mapper
     * @return dao对象
     */
    public static Object getDaoByObj(Object object, String daoSuffix){
        return getDao(object,null,daoSuffix);
    }

    /**
     * 根据传入类名获取dao对象
     * @param className 对象的类名可以是controller 和 service
     * @param daoSuffix  数据交换层的后缀名，如 DogDao 中的Dao或是DogMapper中的Mapper
     * @return dao对象
     */
    public static Object getDaoByClassName(String className,String daoSuffix){
        return getDao(null,className,daoSuffix);
    }

    /**
     * 传入对象或类名获取dao对象
     * @param object 不知名对象，确保他有对应dao层
     * @param simpleClassName  类名（非全名）
     * @param daoSuffix 对于与dao层的后缀，如Repository、Dao等
     * @return dao对象
     */
    public static Object getDao(Object object, String simpleClassName , String daoSuffix) {
        String name = "";
        if(object != null ) {
            Class<?> obj = object.getClass();
            name = obj.getName();
        }else{
            if(simpleClassName.contains("Controller")){
                name = simpleClassName.replace("Controller","");
            }else if(simpleClassName.contains("Service")){
                name = simpleClassName.replace("Service","");
            }
        }
        //如果得到类名含有“.”，那么它可能是类全名，所以再获取一次类名
        if(name.contains(".")) {
            name = ReflectUtil.getSimpleClassName(name);
        }
        Object bean = null;
        try {
            //从IOC容器获取dao对象;
            //这里，复合型名称如：lead Company
            bean = SpringUtil.getBean(ReflectUtil.firstLetterToLowerCase(name) + daoSuffix);
        } catch (Exception e) {
            return bean;
        }
        return bean;
    }

    /**
     * 传入不知名的实体对象，和id参数，获取数据库中的数据
     * @param daoObj dao对象
     * @param paramenter 参数对象
     * @return 获取数据对象
     */
    public static Object getDataById(Object daoObj,Object paramenter){
        Class<?> daoClass = daoObj.getClass();
        Method[] methods = daoClass.getMethods();
        if (paramenter == null) {
            logger.info("主键值无效");
            return null;
        }
        Object[] objs = new Object[]{paramenter};
        for(Method m : methods){
            switch (m.getName()){
                case "findById":
                    return getData(daoObj,"findById",objs);
                case "getById":
                    return getData(daoObj,"getById",objs);
                case "getPrimeryKey":
                    //如果使用MyBatis的逆向工程生成的，方法名可能为这个
                    return getData(daoObj,"getPrimeryKey",objs);
                case "selectByPrimaryKey":
                    //如果使用MyBatis的逆向工程生成的，方法名可能为这个
                    return getData(daoObj,"selectByPrimaryKey",objs);
                    default:
                        break;
            }
//            if(soapResult.getName().equalsIgnoreCase("findById")){
//                findName = soapResult.getName();
//                break;
//            }
//            else if(soapResult.getName().equalsIgnoreCase("getById")){
//                findName = soapResult.getName();
//                break;
//            }
        }
//        return getData(daoObj,findName,paramenter);
        return null;
    }

    /**
     * 传入不知名的实体对象，和id参数，获取数据库中的数据
     * @param daoObj dao对象
     * @param methodName 方法名
     * @param paramenter 一个正常的参数对象，如Integer i 、Dog god
     * @return 数据
     */
    public static Object getData(Object daoObj, String methodName,Object paramenter){
        Object value = null;//反射得到的值
        try {
            Class<?> daoClass = daoObj.getClass();
            Method[] methods = daoClass.getMethods();
            for(Method method : methods){
                if(method.getName().equalsIgnoreCase(methodName)){
                    value = method.invoke(daoObj, paramenter);
                    break;
                }
            }
            //如果dao是继承于Repository的话，查询结果是Optional对象
            if(value instanceof Optional){
                if (((Optional) value).isPresent()) {
                    value = ((Optional) value).get();
                }
            }
//            Method findById = daoClass.getMethod(MethodName, paramenterType);
//            value = findById.invoke(daoObj, paramenter);
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return value;
    }

    /**
     * 传入dao对象，和方法名， 参数集合得到返回值
     *
     * @param daoObj dao对象
     * @param methodName 方法名
     * @param paramenter 参数对象数组（没有数据类型的对象，只有值）
     * @return 数据
     */
    public static Object getData(Object daoObj, String methodName,Object[] paramenter){
        Object value = null;//反射得到的值
        try {
            Class<?> daoClass = daoObj.getClass();
            //这里遍历是为了得到参数类型
            Method[] methods = daoClass.getMethods();
            for(Method method : methods){
                if(method.getName().equalsIgnoreCase(methodName)){
                    //参数类型数组
                    Class<?>[] paramTypes = method.getParameterTypes();
                    //获取方法
                    Method method1 = daoClass.getMethod(method.getName(), paramTypes);
                    //参数类型格式化；这里因为是考虑到数据源的问题，如从请求中获取参数对象，是无法得到参数类型的
                    Object[] newObj = new Object[paramenter.length];
                    //这里有两种，一是对象，二是非对象
                    for (int i = 0 ; i < paramTypes.length ; i++) {
                        if(ReflectUtil.isBaseDefaultType(paramTypes[i])){
                            //基本类型
                            newObj[i] = ReflectUtil.getBaseValueByType(paramTypes[i],paramenter[i]);
                        }else{
                            //对象
                            newObj[i] = ReflectUtil.getActualField(paramTypes[i],paramenter[i]);
                        }
                    }
                    value = method1.invoke(daoObj,newObj);

                    break;
                }
            }
            //如果dao是继承于Repository的话，查询结果是Optional对象
            if(value instanceof Optional){
                if (((Optional) value).isPresent()) {
                    value = ((Optional) value).get();
                }
            }
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
        }
        return value;
    }
    //endregion
}
